using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;

namespace EuropeEngulfed.NET
{
    class SovietUpFrontDefenseRedeploymentMove : Move
    {
        MapInfo.RegionID regionFrom;
        MapInfo.RegionID regionTo;
        PlayingPiece pieceMoved;

        public SovietUpFrontDefenseRedeploymentMove(GameTurn.GameDate gameDate, GameTurn.GamePhase gamePhase, GameTurn.GameSubPhase gameSubPhase, MapInfo.RegionID regionFrom, MapInfo.RegionID regionTo, PlayingPiece pieceMoved)
            : base(gameDate, gamePhase, gameSubPhase)
        {
            this.regionFrom = regionFrom;
            this.regionTo = regionTo;
            this.pieceMoved = pieceMoved;
        }

        protected override void ProcessMove(GameState gameState)
        {
            LandRegionState landRegionMovedFrom = (LandRegionState)gameState.GetRegionState(this.regionFrom);
            LandRegionState landRegionMovedTo = (LandRegionState)gameState.GetRegionState(this.regionTo);

            if (this.pieceMoved is Block)
            {
                Block blockMoved = (Block)this.pieceMoved;
                Block blockToMove = landRegionMovedFrom.RemoveBlock(blockMoved.CountryOwner, blockMoved.getBlockType(), (int)blockMoved.CurrentStrength, (int)blockMoved.MaxStrength, blockMoved.OutOfSupply);
                landRegionMovedTo.AddBlock(blockToMove);
            }
            else if (this.pieceMoved is GroundSupportUnit)
            {
                GroundSupportUnit GSUMoved = (GroundSupportUnit)this.pieceMoved;
                GroundSupportUnit GSUToMove = landRegionMovedFrom.RemoveGSU(GSUMoved.CountryOwner, GSUMoved.OutOfSupply);
                landRegionMovedTo.AddGSU(GSUToMove);
            }

            landRegionMovedTo.CountryControl = MapInfo.CountryID.USSR;
        }

        private bool CheckRussianUpFrontDefenseRequirement(IGameStateInfoProvider gameStateInfoProvider, ref bool blockRequirementMet, ref bool GSURequirementMet, List<MapInfo.RegionID> emptyUpFrontRegions)
        {
            blockRequirementMet = true;
            GSURequirementMet = true;
            emptyUpFrontRegions.Clear();
            /*9.26 SOVIET UP-FRONT DEFENSE: At the end of each Allied playerturn
            beginning with the turn after the Soviet/German Non-Aggression
            Pact takes effect, at least one-half of all Soviet ground units, and all
            Soviet ground-support units, must be within these four areas:
            Bessarabia, Lvov, Brest-Litovsk, and Lithuania. Additionally, each of
            the above four areas must contain at least one ground unit beginning
            with the Jan/Feb 1941 game turn. If either of the above conditions are
            not met, the German player may shift any unexamined Soviet ground
            unit(s) from outside of these areas, of his choosing, until the minimum
            requirements are met. These requirements are lifted beginning
            with the turn the Soviet Union is at war with Germany.*/
            if (gameStateInfoProvider.IsNationConquered(MapInfo.CountryID.Poland))
            {
                if (!gameStateInfoProvider.IsNationAtWar(MapInfo.CountryID.USSR))
                {
                    int totalNumberOfSovietBlocksInHomeAreas = 0;
                    int numBlocksInRegion = 0;
                    int numSovietBlocksInUpFrontAreas = 0;

                    numBlocksInRegion = gameStateInfoProvider.GetRegionsAlliedBlockList(MapInfo.RegionID.Bessarabia).Count;
                    if (numBlocksInRegion == 0)
                        emptyUpFrontRegions.Add(MapInfo.RegionID.Bessarabia);
                    numSovietBlocksInUpFrontAreas += numBlocksInRegion;
                    numBlocksInRegion = gameStateInfoProvider.GetRegionsAlliedBlockList(MapInfo.RegionID.Lvov).Count;
                    if (numBlocksInRegion == 0)
                        emptyUpFrontRegions.Add(MapInfo.RegionID.Lvov);
                    numSovietBlocksInUpFrontAreas += numBlocksInRegion;
                    numBlocksInRegion = gameStateInfoProvider.GetRegionsAlliedBlockList(MapInfo.RegionID.BrestLitovsk).Count;
                    if (numBlocksInRegion == 0)
                        emptyUpFrontRegions.Add(MapInfo.RegionID.BrestLitovsk);
                    numSovietBlocksInUpFrontAreas += numBlocksInRegion;
                    numBlocksInRegion = gameStateInfoProvider.GetRegionsAlliedBlockList(MapInfo.RegionID.Lithuania).Count;
                    if (numBlocksInRegion == 0)
                        emptyUpFrontRegions.Add(MapInfo.RegionID.Lithuania);
                    numSovietBlocksInUpFrontAreas += numBlocksInRegion;

                    if (this.gameTurn.CurrentGameDate < GameTurn.GameDate.JanFeb41)
                        emptyUpFrontRegions.Clear();

                    foreach (MapInfo.RegionID regionID in Enum.GetValues(typeof(MapInfo.RegionID)))
                    {
                        if (MapInfo.IsLandRegion(regionID))
                        {
                            LandRegion landRegion = (LandRegion)MapInfo.GetRegion(regionID);
                            if (landRegion.HomeRegion && landRegion.OriginalCountry == MapInfo.CountryID.USSR || regionID == MapInfo.RegionID.Latvia || regionID == MapInfo.RegionID.Estonia)
                            {
                                totalNumberOfSovietBlocksInHomeAreas += gameStateInfoProvider.GetRegionsAlliedBlockList(regionID).Count;
                                if (gameStateInfoProvider.GetRegionsAlliedGSUList(regionID).Count > 0)
                                    GSURequirementMet = false;
                            }
                        }
                    }

                    if ((numSovietBlocksInUpFrontAreas * 2) < (totalNumberOfSovietBlocksInHomeAreas + numSovietBlocksInUpFrontAreas))
                        blockRequirementMet = false;
                }
            }

            return blockRequirementMet && GSURequirementMet && emptyUpFrontRegions.Count <= 0;
        }

        public void ProcessBlockListModification(List<Block> listToModify, MapInfo.RegionID region)
        {
            if (this.pieceMoved is Block)
            {
                if (this.regionTo == region)
                {
                    Block blockToAdd = ((Block)this.pieceMoved).Copy();
                    listToModify.Add(blockToAdd);
                }
                else if (this.regionFrom == region)
                {
                    foreach (Block blockInList in listToModify)
                    {
                        if (blockInList.Equals((Block)this.pieceMoved))
                        {
                            listToModify.Remove(blockInList);
                            break;
                        }
                    }
                }
            }
        }

        public void ProcessGSUListModification(List<GroundSupportUnit> listToModify, MapInfo.RegionID region)
        {
            if (this.pieceMoved is GroundSupportUnit)
            {
                if (this.regionTo == region)
                {
                    listToModify.Add((GroundSupportUnit)this.pieceMoved);
                }
                else if (this.regionFrom == region)
                {
                    foreach (GroundSupportUnit GSUInList in listToModify)
                    {
                        if (GSUInList.Equals((GroundSupportUnit)this.pieceMoved))
                        {
                            listToModify.Remove(GSUInList);
                            break;
                        }
                    }
                }
            }
        }

        public override bool IsLegal(IGameStateInfoProvider gameStateInfoProvider, ref string ruleString)
        {
            List<MapInfo.RegionID> listOfEmptyRegions = new List<MapInfo.RegionID>();
            bool blockRequirement = true;
            bool GSURequirement = true;

            if(MapInfo.IsLandRegion(this.regionFrom))
            {
                LandRegion landRegionFrom = (LandRegion)MapInfo.GetRegion(this.regionFrom);
                if (landRegionFrom.OriginalCountry != MapInfo.CountryID.USSR)
                {
                    ruleString = "The axis player can only redeploy units that are outside the up front defense areas";
                    return false;
                }

                if (this.regionTo != MapInfo.RegionID.Bessarabia && this.regionTo != MapInfo.RegionID.Lvov && this.regionTo != MapInfo.RegionID.BrestLitovsk && this.regionTo != MapInfo.RegionID.Lithuania)
                {
                    ruleString = "The axis player can only redeploy units to the front defense area";
                    return false;
                }

                if (CheckRussianUpFrontDefenseRequirement(gameStateInfoProvider, ref blockRequirement, ref GSURequirement, listOfEmptyRegions))
                {
                    ruleString = "The Soviet Up Front Defense Requirement Has Already Been Met";
                    return false;
                }

                if (listOfEmptyRegions.Count > 0)
                {
                    if (!listOfEmptyRegions.Contains(this.regionTo))
                    {
                        ruleString = "The Soviet Up Front Defense Requirement of having at least one block in each region must be met first.";
                        return false;
                    }
                }

                if (blockRequirement && !GSURequirement)
                {
                    if (pieceMoved is Block)
                    {
                        ruleString = "The only Soviet Up Front Defense Requirement not met is that of all GSU being in the up front regions. Only GSUs can be moved.";
                        return false;
                    }
                }
            }
            else
            {
                ruleString = "The region redeployed from was not a land region.";
                return false;
            }

            return true;
        }

        public override System.Xml.XmlNode Serialise(System.Xml.XmlDocument xml)
        {
            System.Xml.XmlNode nodeToReturn = xml.CreateElement("Move");
            System.Xml.XmlNode pieceMovedNode = xml.CreateElement("pieceMoved");
            System.Xml.XmlAttribute typeAttr = xml.CreateAttribute("Type");
            System.Xml.XmlAttribute regionFromAttr = xml.CreateAttribute("regionFrom");
            System.Xml.XmlAttribute regionToAttr = xml.CreateAttribute("regionTo");

            nodeToReturn.AppendChild(gameTurn.Serialise(xml));
            typeAttr.Value = this.GetType().ToString();
            regionFromAttr.Value = Enum.GetName(regionFrom.GetType(), regionFrom);
            regionToAttr.Value = Enum.GetName(regionTo.GetType(), regionTo);

            nodeToReturn.Attributes.Append(typeAttr);
            nodeToReturn.Attributes.Append(regionFromAttr);
            nodeToReturn.Attributes.Append(regionToAttr);
            if (pieceMoved is Block)
                pieceMovedNode.AppendChild(((Block)pieceMoved).Serialise(xml));
            else if(pieceMoved is GroundSupportUnit)
                pieceMovedNode.AppendChild(((GroundSupportUnit)pieceMoved).Serialise(xml));
            nodeToReturn.AppendChild(pieceMovedNode);
            return nodeToReturn;
        }

        public new static Move Deserialise(System.Xml.XmlNode node)
        {
            if (node.Attributes["Type"].Value == typeof(SovietUpFrontDefenseRedeploymentMove).ToString() && node.Name == "Move")
            {
                GameTurn parsedGameTurn = GameTurn.Deserialise(node.SelectSingleNode("GameTurn"));
                SovietUpFrontDefenseRedeploymentMove sovietUpFrontDefenseRedeploymentMoveToReturn = new SovietUpFrontDefenseRedeploymentMove(parsedGameTurn.CurrentGameDate, parsedGameTurn.CurrentGamePhase, parsedGameTurn.CurrentGameSubPhase, (MapInfo.RegionID)Enum.Parse(typeof(MapInfo.RegionID), node.Attributes["regionFrom"].Value), (MapInfo.RegionID)Enum.Parse(typeof(MapInfo.RegionID), node.Attributes["regionTo"].Value), PlayingPiece.Deserialise(node.SelectSingleNode("pieceMoved")));
                return sovietUpFrontDefenseRedeploymentMoveToReturn;
            }
            else
                throw new InvalidOperationException();
        }

        public override System.Windows.Forms.TreeNode GetMoveTreeNode(System.Windows.Forms.TreeView treeView)
        {
            if (!treeView.ImageList.Images.ContainsKey(pieceMoved.GetTreeViewImageListKey(true)))
            {
                if (pieceMoved is Block)
                {
                    Bitmap b = new Bitmap(treeView.ImageList.ImageSize.Width, treeView.ImageList.ImageSize.Height);
                    Graphics g = Graphics.FromImage(b);
                    PlayingPieceGraphics.PaintBlockFace(g, (Block)pieceMoved, new Rectangle(0, 0, treeView.ImageList.ImageSize.Width, treeView.ImageList.ImageSize.Height), true);
                    treeView.ImageList.Images.Add(pieceMoved.GetTreeViewImageListKey(true), b);
                }
                else if (pieceMoved is GroundSupportUnit)
                {
                    Bitmap b = new Bitmap(treeView.ImageList.ImageSize.Width, treeView.ImageList.ImageSize.Height);
                    Graphics g = Graphics.FromImage(b);
                    PlayingPieceGraphics.PaintGSUFace(g, (GroundSupportUnit)pieceMoved, new Rectangle(0, 0, treeView.ImageList.ImageSize.Width, treeView.ImageList.ImageSize.Height), true);
                    treeView.ImageList.Images.Add(pieceMoved.GetTreeViewImageListKey(true), b);
                }
            }
            return new System.Windows.Forms.TreeNode("Axis redeployment of soviet up front defenses from " + MapInfo.GetRegionName(this.regionFrom) + " to " + MapInfo.GetRegionName(this.regionTo), treeView.ImageList.Images.IndexOfKey(pieceMoved.GetTreeViewImageListKey(true)), treeView.ImageList.Images.IndexOfKey(pieceMoved.GetTreeViewImageListKey(true)));
        }

        public override string GetStringForNetworkMessage()
        {
            return "Axis redeploy piece from " + Enum.GetName(typeof(MapInfo.RegionID), this.regionFrom) + " to " + Enum.GetName(typeof(MapInfo.RegionID), this.regionTo);
        }
    }
}
